#!/usr/bin/env python
# encoding: utf-8
"""
@author: youfeng
@email: youfeng243@163.com
@license: Apache Licence
@file: proxy_handler_.py
@time: 2017/12/20 10:19
"""

# 代理管理对象
import random
import threading
import time

import requests

# 代理使用总入口
from config.proxy_conf import StaticProxyConf, DynamicProxyConf
from proxy.proxy_type import ProxyType
from common import util


class ProxyHandler(object):

    def __init__(self, log=None):
        self.__is_running = True
        self.log = log

        self.log.info("初始化代理信息...")

        # 管理现在可用的静态代理
        self.__static_proxy_list = self.__update_static_proxy()
        self.__static_length = len(self.__static_proxy_list)
        self.__static_point = random.randint(0, self.__static_length)

        # 静态代理更新线程
        self.__static_update_thread = threading.Thread(target=self.__static_update_run, )
        self.__static_update_thread.setDaemon(True)
        self.__static_update_thread.start()

        self.log.info("代理初始化完成...")

    def __del__(self):
        self.close()

    def close(self):
        self.__is_running = False
        self.__static_update_thread.join()

    # 更新静态代理
    def __update_static_proxy(self):

        for _ in xrange(3):
            proxy_list = []
            try:
                r = requests.get(StaticProxyConf.URL, timeout=10)
                if r is None or r.status_code != 200:
                    self.log.error("更新静态代理网络异常...")
                    continue

                line_list = r.text.strip().split('\n')
                for line in line_list:
                    line = line.strip().strip("\r").strip("\n")
                    if len(line) <= 0:
                        continue

                    proxy = {'http': line}

                    proxy_list.append(proxy)
                self.log.info('静态代理更新代理成功: length = {}'.format(len(proxy_list)))
                return proxy_list
            except Exception as e:
                self.log.error('访问静态代理链接异常: ')
                self.log.exception(e)
        return []

    def __long_time_sleep(self, long_time):
        count = 0
        while count < long_time and self.__is_running:
            count += 1
            time.sleep(1)

    # 静态代理更新线程
    def __static_update_run(self):

        self.log.info("启动静态代理更新线程...")

        while self.__is_running:
            # 更新静态代理
            static_proxy_list = self.__update_static_proxy()

            static_proxy_length = len(static_proxy_list)
            if static_proxy_length > 0:
                self.__static_proxy_list = static_proxy_list
                self.__static_length = static_proxy_length
                self.log.info("更新静态代理完成: __static_length = {}".format(self.__static_length))

            self.log.info("完成静态代理更新, 休眠3600秒")

            # 每隔1个小时更新一次
            self.__long_time_sleep(random.randint(3600, 4600))
        self.log.info("正常退出静态代理后台更新线程...")

    def get_proxy(self, proxy_type=ProxyType.KUNPENG_STATIC, host=None):
        if proxy_type == ProxyType.KUNPENG_STATIC:
            return self.get_static_proxy()

        if proxy_type == ProxyType.KUNPENG_DYNAMIC:
            return self.get_dynamic_proxy(host)

        if proxy_type == ProxyType.YIZHOU_DYNAMIC:
            return self.__get_gateway_proxy(host)

        # 异常情况下都返回静态代理
        return self.get_static_proxy()

    # 获取代理
    def get_dynamic_proxy(self, host=None):
        if host is None:
            host = "spider-platform"
        for _ in xrange(3):
            try:
                r = requests.get('http://{}:{}/proxy/{}'.format(
                    DynamicProxyConf.HOST,
                    DynamicProxyConf.PORT,
                    host),
                    timeout=10)
                if r is None or r.status_code != 200 or 'failed' in r.text or 'False' in r.text:
                    time.sleep(1)
                    self.log.warn("动态代理服务异常, 重试...")
                    continue

                self.log.info('鲲鹏 ip = {ip}'.format(ip=r.text))
                proxies = {'http': 'http://{host}'.format(host=r.text)}
                return proxies
            except Exception as e:
                self.log.error("动态代理访问异常:")
                self.log.exception(e)
                time.sleep(1)
        return {}

    # 获取静态代理
    def get_static_proxy(self):

        if self.__static_point >= self.__static_length:
            self.__static_point = 0

        try:
            if self.__static_length > 0:
                proxy = self.__static_proxy_list[self.__static_point]
                self.__static_point += 1
                self.log.info('静态代理 ip = {}'.format(proxy))
                return proxy

            self.log.error("当前静态代理长度为空: __static_length = {} actual length = {}".format(
                self.__static_length, len(self.__static_proxy_list)))
            self.__static_length = len(self.__static_proxy_list)
        except Exception as e:
            self.log.error("静态代理取址失败: point = {} cur length = {} actual length = {}".format(
                self.__static_point, self.__static_length, len(self.__static_proxy_list)))
            self.log.exception(e)
            return {}

        return {}


    GATEWAY_PROXY_URL = "http://192.168.0.90:9600/proxy?tag=yizhou&host={}"

    # 获得网关代理
    def __get_gateway_proxy(self, host):
        for _ in xrange(3):
            try:
                r = requests.get(self.GATEWAY_PROXY_URL.format(host),
                                 timeout=10)
                if r is None or r.status_code != 200:
                    time.sleep(1)
                    self.log.warn("代理网关访问异常, 重试...")
                    continue

                proxy_dict = util.json_loads(r.text)
                if proxy_dict.get("status") != "ok":
                    time.sleep(1)
                    self.log.warn("代理网关获取代理异常: text = {}".format(r.text))
                    continue

                proxy = proxy_dict.get("proxy")
                if proxy is None:
                    time.sleep(1)
                    self.log.warn("代理网关获取代理异常: text = {}".format(r.text))
                    continue

                self.log.info('网关 ip = {}'.format(proxy))
                proxies = {'http': proxy}
                return proxies
            except Exception as e:
                self.log.error("动态代理访问异常:")
                self.log.exception(e)
                time.sleep(1)
        return {}
